﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Net;

namespace Sofire.DataComm.Remoting.Server.Settings
{
    /// <summary>
    /// 主机配置信息。
    /// </summary>
    public class HostSetting : SettingBase, IEnumerable<ServiceSetting>
    {
        /// <summary>
        /// 应用域配置信息。
        /// </summary>
        internal ApplicationSetting _Application;
        /// <summary>
        /// 表示应用域配置信息。
        /// </summary>
        public ApplicationSetting Application
        {
            get
            {
                return this._Application;
            }
        }

        private int _Port;
        /// <summary>
        /// 主机端口。
        /// </summary>
        public int Port
        {
            get
            {
                return this._Port;
            }
            set
            {
                RemotingApplication.ThorwEceptionWithIsOpen();
                this._Port = value;
            }
        }

        private Dictionary<string, ServiceSetting> _Services;

        private IPAddress _Address;
        /// <summary>
        /// 设置或获取网际协议地址。
        /// </summary>
        public IPAddress Address
        {
            get
            {
                return this._Address;
            }
            set
            {
                RemotingApplication.ThorwEceptionWithIsOpen();
                this._Address = value;
            }
        }

        private int _MaxConnectionCount = 102400;
        /// <summary>
        /// 获取服务器的最大连接数。默认为“102400”。
        /// </summary>
        public int MaxConnectionCount
        {
            get
            {
                return this._MaxConnectionCount;
            }
        }

        private int _MaxReceiveBufferSize = 2048;
        /// <summary>
        /// 获取接收的最大缓冲区长度。默认为“2048”。
        /// </summary>
        public int MaxReceiveBufferSize
        {
            get
            {
                return this._MaxReceiveBufferSize;
            }
        }
        private int _ListenBacklog = 10240;
        /// <summary>
        /// 获取最大的侦听并发数。默认为“10240”。
        /// </summary>
        public int ListenBacklog
        {
            get
            {
                return this._ListenBacklog;
            }
        }

        /// <summary>
        /// 获取主机配置下的所有服务配置。
        /// </summary>
        public IEnumerable<ServiceSetting> Services
        {
            get
            {
                if(this._Services == null) return new List<ServiceSetting>(0);
                else return this._Services.Values;
            }
        }

        /// <summary>
        /// 获取主机的服务数目。
        /// </summary>
        public int Count
        {
            get
            {
                return this._Services.Count;
            }
        }

        /// <summary>
        /// 获取指定服务名称的 <see cref="Sofire.DataComm.Remoting.Server.Settings.ServiceSetting"/>。
        /// </summary>
        /// <param name="serviceName">服务的名称。</param>
        /// <returns>返回查找到的服务或 null 值。</returns>
        public ServiceSetting this[string serviceName]
        {
            get
            {
                ServiceSetting service;
                if(this._Services.TryGetValue(serviceName, out service)) return service;
                return null;
            }
        }

        /// <summary>
        /// 初始化配置。
        /// </summary>
        /// <param name="element">XML 配置元素。</param>
        internal override void Initialization(XmlElement element)
        {
            base.Initialization(element);

            var value = element.TryGetAttribute(PortAttribute);
            if(string.IsNullOrEmpty(value)) throw this.CreateException(ServerErrorCode.EmptyAttribute, PortAttribute);

            int iValue;
            if(int.TryParse(value, out iValue) && iValue > 0 && iValue < 65536) this._Port = iValue;
            else throw this.CreateException(ServerErrorCode.InvalidPort, PortAttribute, value);

            value = element.TryGetAttribute(MaxConnectionCountAttribute);
            if(!string.IsNullOrEmpty(value))
            {
                if(!int.TryParse(value, out iValue) || iValue < 1) throw this.CreateException(ServerErrorCode.MaxConnectionCount, MaxConnectionCountAttribute, value);
                this._MaxConnectionCount = iValue;
            }

            value = element.TryGetAttribute(MaxReceiveBufferSizeAttribute);
            if(!string.IsNullOrEmpty(value))
            {
                if(!int.TryParse(value, out iValue) || iValue < 1) throw this.CreateException(ServerErrorCode.MaxReceiveBufferSize, MaxReceiveBufferSizeAttribute, value);
                this._MaxReceiveBufferSize = iValue;
            }

            value = element.TryGetAttribute(ListenBacklogAttribute);
            if(!string.IsNullOrEmpty(value))
            {
                if(!int.TryParse(value, out iValue) || iValue < 1) throw this.CreateException(ServerErrorCode.ListenBacklog, ListenBacklogAttribute, value);
                this._ListenBacklog = iValue;
            }

            var serviceElements = element.SelectNodes("Service");
            this._Services = new Dictionary<string, ServiceSetting>(serviceElements.Count, StringComparer.OrdinalIgnoreCase);

            value = element.TryGetAttribute(AddressAttribute);
            try
            {
                this._Address = NetExts.ParseAddress(value);
            }
            catch(Exception) { throw this.CreateException(ServerErrorCode.InvalidAddress, AddressAttribute, value); }

            foreach(XmlElement serviceElement in serviceElements)
            {
                ServiceSetting service = new ServiceSetting();
                service._Host = this;
                service.Initialization(serviceElement);
                this._Services.Add(service.Name, service);
            }
        }

        internal HostSetting() { }

        #region AddService<TContract, TService>

        /// <summary>
        /// 创建并添加一个服务配置。
        /// </summary>
        /// <typeparam name="TContract">服务契约的类型。</typeparam>
        /// <typeparam name="TService"></typeparam>
        /// <param name="serviceName">服务的名称。</param>
        /// <param name="serviceInstance">服务的注册实例。</param>
        /// <returns>返回创建成功的服务配置。</returns>
        public ServiceSetting AddService<TContract, TService>(string serviceName, TService serviceInstance)
            where TService : class,TContract
        {
            return this.AddService<TContract, TService>(serviceName, serviceInstance, this.ReturnsError);
        }

        /// <summary>
        /// 创建并添加一个服务配置。
        /// </summary>
        /// <typeparam name="TContract">服务契约的类型。</typeparam>
        /// <typeparam name="TService"></typeparam>
        /// <param name="serviceName">服务的名称。</param>
        /// <param name="serviceInstance">服务的注册实例。</param>
        /// <param name="returnsError">指示在远程发生错误时是否返回异常的信息。</param>
        /// <returns>返回创建成功的服务配置。</returns>
        public ServiceSetting AddService<TContract, TService>(string serviceName, TService serviceInstance, bool returnsError)
            where TService : class,TContract
        {
            RemotingApplication.ThorwEceptionWithIsOpen();

            if(this._Services == null) this._Services = new Dictionary<string, ServiceSetting>(StringComparer.OrdinalIgnoreCase);

            if(string.IsNullOrEmpty(serviceName)) throw new ArgumentException("添加的服务名称不能为空！");
            if(this._Services.ContainsKey(serviceName)) throw new ArgumentException("添加的服务名称“" + serviceName + "”已存在。");
            if(serviceInstance == null) throw new ArgumentNullException("serviceInstance");
            var contractType = typeof(TContract);
            if(!contractType.IsInterface) throw new ArgumentException("添加的服务“" + serviceName + "”契约不是一个接口类型“" + contractType.FullName + "”。");


            ServiceSetting serviceSetting = new ServiceSetting();
            serviceSetting._Host = this;
            serviceSetting.Instance = serviceInstance;
            serviceSetting.Type = typeof(TService);
            serviceSetting.Contract = contractType;
            serviceSetting.InstanceMode = InstanceRegisterMode.Custom;
            serviceSetting.ReturnsError = returnsError;
            return serviceSetting;
        }

        #endregion

        #region AddService<TContract>

        /// <summary>
        /// 创建并添加一个服务配置。
        /// </summary>
        /// <typeparam name="TContract">服务契约的类型。</typeparam>
        /// <param name="serviceName">服务的名称。</param>
        /// <param name="serviceType">服务的类型。</param>
        /// <returns>返回创建成功的服务配置。</returns>
        public ServiceSetting AddService<TContract>(string serviceName, Type serviceType)
        {
            return this.AddService(serviceName, serviceType, typeof(TContract), InstanceRegisterMode.Default, this.ReturnsError);
        }

        /// <summary>
        /// 创建并添加一个服务配置。
        /// </summary>
        /// <typeparam name="TContract">服务契约的类型。</typeparam>
        /// <param name="serviceName">服务的名称。</param>
        /// <param name="serviceType">服务的类型。</param>
        /// <param name="instanceMode">指示服务实例的注册模式。</param>
        /// <returns>返回创建成功的服务配置。</returns>
        public ServiceSetting AddService<TContract>(string serviceName, Type serviceType, InstanceRegisterMode instanceMode)
        {
            return this.AddService(serviceName, serviceType, typeof(TContract), instanceMode, this.ReturnsError);
        }

        /// <summary>
        /// 创建并添加一个服务配置。
        /// </summary>
        /// <typeparam name="TContract">服务契约的类型。</typeparam>
        /// <param name="serviceName">服务的名称。</param>
        /// <param name="serviceType">服务的类型。</param>
        /// <param name="instanceMode">指示服务实例的注册模式。</param>
        /// <param name="returnsError">指示在远程发生错误时是否返回异常的信息。</param>
        /// <returns>返回创建成功的服务配置。</returns>
        public ServiceSetting AddService<TContract>(string serviceName, Type serviceType, InstanceRegisterMode instanceMode, bool returnsError)
        {
            return this.AddService(serviceName, serviceType, typeof(TContract), instanceMode, returnsError);
        }

        #endregion

        #region AddService

        /// <summary>
        /// 创建并添加一个服务配置。
        /// </summary>
        /// <param name="serviceName">服务的名称。</param>
        /// <param name="serviceType">服务的类型。</param>
        /// <param name="contractType">服务契约的类型。</param>
        /// <returns>返回创建成功的服务配置。</returns>
        public ServiceSetting AddService(string serviceName, Type serviceType, Type contractType)
        {
            return this.AddService(serviceName, serviceType, contractType, InstanceRegisterMode.Default, this.ReturnsError);
        }

        /// <summary>
        /// 创建并添加一个服务配置。
        /// </summary>
        /// <param name="serviceName">服务的名称。</param>
        /// <param name="serviceType">服务的类型。</param>
        /// <param name="contractType">服务契约的类型。</param>
        /// <param name="instanceMode">指示服务实例的注册模式。</param>
        /// <returns>返回创建成功的服务配置。</returns>
        public ServiceSetting AddService(string serviceName, Type serviceType, Type contractType, InstanceRegisterMode instanceMode)
        {
            return this.AddService(serviceName, serviceType, contractType, instanceMode, this.ReturnsError);
        }

        /// <summary>
        /// 创建并添加一个服务配置。
        /// </summary>
        /// <param name="serviceName">服务的名称。</param>
        /// <param name="serviceType">服务的类型。</param>
        /// <param name="contractType">服务契约的类型。</param>
        /// <param name="instanceMode">指示服务实例的注册模式。</param>
        /// <param name="returnsError">指示在远程发生错误时是否返回异常的信息。</param>
        /// <returns>返回创建成功的服务配置。</returns>
        public ServiceSetting AddService(string serviceName, Type serviceType, Type contractType, InstanceRegisterMode instanceMode, bool returnsError)
        {
            RemotingApplication.ThorwEceptionWithIsOpen();

            if(this._Services == null) this._Services = new Dictionary<string, ServiceSetting>(StringComparer.OrdinalIgnoreCase);

            if(string.IsNullOrEmpty(serviceName)) throw new ArgumentException("添加的服务名称不能为空！");
            if(this._Services.ContainsKey(serviceName)) throw new ArgumentException("添加的服务名称“" + serviceName + "”已存在。");

            //ServiceSetting.CheckServiceType(serviceName, serviceType, contractType);

            ServiceSetting serviceSetting = new ServiceSetting();
            serviceSetting._Host = this;
            serviceSetting.Type = serviceType;
            serviceSetting.Contract = contractType;
            serviceSetting.InstanceMode = instanceMode;
            serviceSetting.ReturnsError = returnsError;

            return serviceSetting;
        }

        #endregion

        #region IEnumerable<ServiceSetting> 成员

        IEnumerator<ServiceSetting> IEnumerable<ServiceSetting>.GetEnumerator()
        {
            return this._Services.Values.GetEnumerator();
        }

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return this._Services.Values.GetEnumerator();
        }

        #endregion

        internal override SettingException CreateException(ServerErrorCode errorCode, string propertyName, string propertyValue)
        {
            return new SettingException(errorCode, propertyName, propertyValue)
            {
                _Application = this._Application,
                _Host = this
            };
        }
    }
}
